package ch.bfh.mgb.hamilton.entities;

import java.util.Random;

import ch.bfh.mgb.hamilton.simulation.FoodContainer;
import ch.bfh.mgb.hamilton.simulation.SimulationParameters;

/**
 * Class representing a member of the population
 */
public class Robot {
	private final static Random rand = new Random();
	
	private long robotID;
	private boolean isMale;
	private double reproductionFrequency;
	private int fertility;
	private double costs;
	private double profits;
	private int timeToLive;
	private int[] foodBehaviour;
	private int smallFoodCollected;
	private int mediumFoodCollected;
	private int bigFoodCollected;
	//4 properties only for DiversificationPopulation
	private int canGiveFood;
	private int needFood;
	private long parent1RobotID;
	private long parent2RobotID;
	
	public Robot(boolean isMale, double reproductionFrequency, int fertility, long robotID, int timeToLive, int[] foodBehaviour){
		this.isMale=isMale;
		this.reproductionFrequency = reproductionFrequency;
		this.fertility = fertility;
		this.robotID=robotID;
		this.timeToLive = timeToLive;
		this.foodBehaviour = foodBehaviour;
		smallFoodCollected = 0;
		mediumFoodCollected = 0;
		bigFoodCollected = 0;
		costs = 0;
		profits = 0;
		int canGiveFood=0;
		int needFood=0;
		long parent1RobotID=0;
		long parent2RobotID=0;
	}	
	
	public Robot(boolean isMale, double reproductionFrequency, int fertility, long robotID, int timeToLive){
		this(isMale, reproductionFrequency, fertility, robotID, timeToLive, createFoodBehaviour());
	}
	
	// Random-generated food collection behaviour
	private static int[] createFoodBehaviour() {
		int[] beh = new int[SimulationParameters.foodIterations];
		
		for(int i = 0; i < beh.length ;i++) {
			beh[i] = (rand.nextInt(SimulationParameters.maxFoodBehaviourStates)) + 1;
		}
		
		return beh;
	}
	
	@Override
	public String toString() {
		return "ID:" + String.format("%06d", robotID) 
			+ " reproductionFrequency:" + String.format("%.5f", reproductionFrequency) 
			+ " fertility:" + fertility 
			+ " foodCollectionBehaviour:[" + arrayToString(foodBehaviour,";") + "]"
			+ " foodCollected[s,m,b]:["+smallFoodCollected+","+mediumFoodCollected+","+bigFoodCollected+"]";
	}
	
	private String arrayToString(int[] a, String separator) {
	    StringBuilder result = new StringBuilder();
	    if (a.length > 0) {
	        result.append(a[0]);
	        for (int i=1; i<a.length; i++) {
	            result.append(separator);
	            result.append(a[i]);
	        }
	    }
	    return result.toString();
	}

	public long getParent1RobotID() {
		return parent1RobotID;
	}

	public void setParent1RobotID(long parent1RobotID) {
		this.parent1RobotID = parent1RobotID;
	}

	public long getParent2RobotID() {
		return parent2RobotID;
	}

	public void setParent2RobotID(long parent2RobotID) {
		this.parent2RobotID = parent2RobotID;
	}

	public int getCanGiveFood() {
		return canGiveFood;
	}

	public void setCanGiveFood(int canGiveFood) {
		this.canGiveFood = canGiveFood;
	}

	public int getNeedFood() {
		return needFood;
	}

	public void setNeedFood(int needFood) {
		this.needFood = needFood;
	}

	public boolean isMale() {
		return isMale;
	}

	public double getReproductionFrequency() {
		return reproductionFrequency;
	}

	public int getFertility() {
		return fertility;
	}

	public double getCosts() {
		return costs;
	}

	public void setCosts(double costs) {
		this.costs = costs;
	}

	public double getProfits() {
		return profits;
	}

	public void setProfits(double profits) {
		this.profits = profits;
	}

	public long getRobotID() {
		return robotID;
	}

	public int getTimeToLive() {
		return timeToLive;
	}

	public void setTimeToLive(int timeToLive) {
		this.timeToLive = timeToLive;
	}

	// returns either FoodContainer.SMALL, FoodContainer.MEDIUM or FoodContainer.BIG
	// based on the behaviour of the current round
	public Food getCurrentFoodBehaviour(int round) {
		
		switch(foodBehaviour[round]) {
		case 1:
			return FoodContainer.SMALL;
		case 2:
			if (rand.nextInt(10) < 7) {
				return FoodContainer.SMALL;
			}
			return FoodContainer.MEDIUM;
		case 3:
			if (rand.nextInt(10) < 4) {
				return FoodContainer.SMALL;
			}
			return FoodContainer.MEDIUM;
		case 4:
			if (rand.nextInt(10) < 1) {
				return FoodContainer.SMALL;
			}
			return FoodContainer.MEDIUM;
		case 5:
			return FoodContainer.MEDIUM;
		case 6:
			if (rand.nextInt(10) < 9) {
				return FoodContainer.MEDIUM;
			}
			return FoodContainer.BIG;
		case 7:
			if (rand.nextInt(10) < 6) {
				return FoodContainer.MEDIUM;
			}
			return FoodContainer.BIG;
		case 8:
			if (rand.nextInt(10) < 3) {
				return FoodContainer.MEDIUM;
			}
			return FoodContainer.BIG;
		case 9:
			return FoodContainer.BIG;
		}
		
		throw new RuntimeException("no correct FoodBehaviour found");
	}

	public int[] getFoodBehaviour() {
		return foodBehaviour;
	}

	public void setFoodBehaviour(int[] foodBehaviour) {
		this.foodBehaviour = foodBehaviour;
	}

	public int getSmallFoodCollected() {
		return smallFoodCollected;
	}

	public void setSmallFoodCollected(int smallFoodCollected) {
		this.smallFoodCollected = smallFoodCollected;
	}

	public int getMediumFoodCollected() {
		return mediumFoodCollected;
	}

	public void setMediumFoodCollected(int mediumFoodCollected) {
		this.mediumFoodCollected = mediumFoodCollected;
	}

	public int getBigFoodCollected() {
		return bigFoodCollected;
	}

	public void setBigFoodCollected(int bigFoodCollected) {
		this.bigFoodCollected = bigFoodCollected;
	}
	
	/**
	 * Counts the energy-value by multiplying the energy values of all collected
	 * divided by the weight of the specific food. -> if the weight is 3, then
	 * the energy brought to the community is BIG.energy / 3
	 */
	public double getFoodCount() {
		return (smallFoodCollected * FoodContainer.SMALL.energy) / FoodContainer.SMALL.weight 
			+ (mediumFoodCollected * FoodContainer.MEDIUM.energy) / FoodContainer.MEDIUM.weight 
			+ (bigFoodCollected * FoodContainer.BIG.energy) / FoodContainer.BIG.weight ;
	}
	
}
